﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using System.Linq.Expressions;
using System.Reflection;

namespace Eazy.Test
{
    public class LazyTypeTestClass
    {
        public LazyTypeTestClass()
        {
            this.ArgCountOfUsedConstructor = 0;
        }

        public LazyTypeTestClass(int i)
        {
            this.ArgCountOfUsedConstructor = 1;
        }

        public LazyTypeTestClass(int i, DateTime dt)
        {
            this.ArgCountOfUsedConstructor = 2;
        }

        public LazyTypeTestClass(int i0, int i1, int i2, int i3, int i4, DateTime dt)
        {
            this.ArgCountOfUsedConstructor = 6;
            this.DateTimeSetByConstructor = dt;
        }

        public DateTime DateTimeSetByConstructor;

        public int ArgCountOfUsedConstructor = -1;

        public int NonVirtualProperty { get; set; }

        public virtual int VirtualProperty { get; set; }

        public virtual int ReadOnlyProperty { get; private set; }
    }

    public class LazyProxyTest
    {
        [Fact]
        public void InitializeByProperConstructors()
        {
            var lazyProxy = new LazyProxy<LazyTypeTestClass>();
            Assert.NotNull(lazyProxy.ProxyType);
            Assert.Equal(4, lazyProxy.ConstructorCount);

            var byZero = (LazyTypeTestClass)Activator.CreateInstance(lazyProxy.ProxyType);
            Assert.Equal(0, byZero.ArgCountOfUsedConstructor);

            var byOne = (LazyTypeTestClass)Activator.CreateInstance(lazyProxy.ProxyType, 1);
            Assert.Equal(1, byOne.ArgCountOfUsedConstructor);

            var byTwo = (LazyTypeTestClass)Activator.CreateInstance(lazyProxy.ProxyType, 1, DateTime.Now);
            Assert.Equal(2, byTwo.ArgCountOfUsedConstructor);

            var dt = DateTime.Now;
            var bySix = (LazyTypeTestClass)Activator.CreateInstance(lazyProxy.ProxyType, 1, 2, 3, 4, 5, DateTime.Now);
            Assert.Equal(6, bySix.ArgCountOfUsedConstructor);
            Assert.Equal(dt, bySix.DateTimeSetByConstructor);
        }

        [Fact]
        public void OverrideProperProperties()
        {
            var lazyProxy = new LazyProxy<LazyTypeTestClass>();
            Assert.NotNull(lazyProxy.ProxyType);
            Assert.Equal(1, lazyProxy.PropertyCount);

            var instance = (LazyTypeTestClass)Activator.CreateInstance(lazyProxy.ProxyType);
            instance.VirtualProperty = 1;
            Assert.Equal(1, instance.VirtualProperty);
        }

        [Fact]
        public void LazyLoading()
        {
            var lazyProxy = new LazyProxy<LazyTypeTestClass>();
            var instance = (LazyTypeTestClass)Activator.CreateInstance(lazyProxy.ProxyType);

            Expression<Func<LazyTypeTestClass, int>> expr = c => c.VirtualProperty;
            var property = (expr.Body as MemberExpression).Member as PropertyInfo;

            int count = 0;
            instance.NonVirtualProperty = count;
            lazyProxy.SetLazyLoader(property, instance, (Func<int>)(() => count));
            count = 10;

            Assert.Equal(0, instance.NonVirtualProperty);
            Assert.Equal(10, instance.VirtualProperty);

            count = 100;
            Assert.Equal(10, instance.VirtualProperty);
        }
    }
}
